package mst;

import java.util.ArrayList;
import java.util.List;

public class MST {

	private List<City> data;
	
	private double[][] ds;
	
	public MST(List<City> data){
		this.data=data;
	}
	
	public List<Edge> compute(){
		// 距离矩阵
		ds = new double[data.size()][data.size()];

		for (int i = 0; i < data.size(); i++) {
			City city1 = data.get(i);
			for (int j = i + 1; j < data.size(); j++) {
				City city2 = data.get(j);
				ds[i][j] = getDistance(city1, city2);
				// 矩阵 对称性
				ds[j][i] = ds[i][j];
			}
			ds[i][i] = 0.0;
		}	

		boolean[] isMst=new boolean[data.size()];
		isMst[0]=true;
		Edge edge=null;
		List<Edge> edges=new ArrayList<Edge>();
        while((edge=findMinEdge(isMst))!=null){
        	edges.add(edge);	
        	
        	//标记为已知MST数据点
        	isMst[edge.getJ()]=true;
        }
		return edges;
		
	}
	
	//找出 和 已知的MST数据点 最小距离的点
	private Edge findMinEdge(boolean[] isMst){
		//初始化无限大
		double minds = Double.POSITIVE_INFINITY;
		int minI=-1;
		int minJ=-1;
		Edge edge=null;
		for(int i=0;i<ds.length;i++){
			if(isMst[i]==true){
				for(int j=0;j<ds.length;j++){
					if(isMst[j]==false){
					    if(minds>ds[i][j]){
					    	minds=ds[i][j];
					    	minI=i;
					    	minJ=j;
						}
					}
				}
			}
		}
		if(minI>-1){
			edge=new Edge(minI,minJ,minds);
		}
		return edge;
	}
	
	// 计算空间距离
	private double getDistance(City city1, City city2) {
		 double  distance=Math.pow(city1.getX()-city2.getX(),2)+Math.pow(city1.getY()-city2.getY(),2);
		 return Math.sqrt(distance);
		 
	}
	
	public static void main(String[] args) {
		List<City> citys = new ArrayList<City>();

		City city0 = new City();
		city0.setName("北 京");
		city0.setX(116.28);
		city0.setY(39.54);
		citys.add(city0);
		
		City city1 = new City();
		city1.setName("上 海");
		city1.setX(121.29);
		city1.setY(31.14);
		citys.add(city1);

		City city2 = new City();
		city2.setName("天 津");
		city2.setX(117.11);
		city2.setY(39.09);
		citys.add(city2);

		City city3 = new City();
		city3.setName("重 庆");
		city3.setX(106.32);
		city3.setY(29.32);
		citys.add(city3);

		City city4 = new City();
		city4.setName("哈尔滨");
		city4.setX(126.41);
		city4.setY(45.45);
		citys.add(city4);

		City city5 = new City();
		city5.setName("长 春");
		city5.setX(125.19);
		city5.setY(43.52);
		citys.add(city5);

		City city6 = new City();
		city6.setName("南 京");
		city6.setX(118.50);
		city6.setY(32.02);
		citys.add(city6);

		City city7 = new City();
		city7.setName("武 汉");
		city7.setX(114.21);
		city7.setY(30.37);
		citys.add(city7);

		City city8 = new City();
		city8.setName("台 北");
		city8.setX(121.31);
		city8.setY(25.03);
		citys.add(city8);

		City city9 = new City();
		city9.setName("香 港");
		city9.setX(114.10);
		city9.setY(22.18);
		citys.add(city9);
		
		MST mst=new MST(citys);
		List<Edge> edges=mst.compute();
		
		System.out.println("------------------线路最佳方案如下------------------");
		for(Edge edge:edges){
			City from=citys.get(edge.getI());
			City to=citys.get(edge.getJ());
			double length=edge.getW();
			System.out.println(edge.getI()+"========>"+edge.getJ());
			System.out.println(from.getName()+"到"+to.getName()+",全长"+length);
		}

	}

}

/**
 * 城市
 * 
 * @author duyf
 * 
 */
class City {

	private String name;
	// 经度
	private double x;

	// 纬度
	private double y;

	public double getX() {
		return x;
	}

	public void setX(double x) {
		this.x = x;
	}

	public double getY() {
		return y;
	}

	public void setY(double y) {
		this.y = y;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		City other = (City) obj;
		if (this.getX() == other.getX() && this.getY() == other.getY()) {
			return true;
		}
		return false;
	}
}

/**
 * 边距 包含两端数据点(城市)的索引
 * @author duyf
 *
 */
class Edge {
    
    private int i;
    private int j;
    private double w;

    Edge(int i, int j, double w) {
        this.i = i;
        this.j = j;
        this.w = w;
    }

    public int getI() {
        return i;
    }

    public int getJ() {
        return j;
    }

    public double getW() {
        return w;
    }

}
